package com.yhy.wxzn.wcs.device.rgv;

import cn.hutool.core.util.StrUtil;
import com.yhy.wxzn.common.utils.SpringUtil;
import com.yhy.wxzn.common.utils.WcsUtils;
import com.yhy.wxzn.wcs.device.plc.task.PlcTaskThread;
import com.yhy.wxzn.wcs.device.rgv.bean.Coord;
import com.yhy.wxzn.wcs.device.rgv.bean.FourWayRgv;
import com.yhy.wxzn.wcs.device.rgv.bean.Node;
import com.yhy.wxzn.wcs.device.rgv.bean.Route;
import com.yhy.wxzn.wcs.device.rgv.core.avoid.AvoidCentralManagerThread;
import com.yhy.wxzn.wcs.device.rgv.core.avoid.AvoidHandler;
import com.yhy.wxzn.wcs.device.rgv.core.pathplanning.PathPlaningHandlerImpl;
import com.yhy.wxzn.wcs.device.rgv.core.plc.ToRgv;
import com.yhy.wxzn.wcs.device.rgv.enums.*;
import com.yhy.wxzn.wcs.device.rgv.exception.ActivelyAvoidFailureException;
import com.yhy.wxzn.wcs.device.rgv.exception.AddLockTimeOutException;
import com.yhy.wxzn.wcs.device.rgv.exception.PalletDownStatusException;
import com.yhy.wxzn.wcs.device.rgv.exception.PalletUpStatusException;
import com.yhy.wxzn.wcs.entity.WcsFourWayTask;
import com.yhy.wxzn.wcs.entity.WcsTask;
import com.yhy.wxzn.wcs.enums.PlcTaskProgress;
import com.yhy.wxzn.wcs.enums.RgvTaskAssignStatus;
import com.yhy.wxzn.wcs.enums.TaskStatus;
import com.yhy.wxzn.wcs.enums.TaskType;
import com.yhy.wxzn.wcs.service.impl.WcsFourWayTaskServiceImpl;
import com.yhy.wxzn.wcs.service.impl.WcsMapInfoServiceImpl;
import com.yhy.wxzn.wcs.service.impl.WcsTaskServiceImpl;
import com.yhy.wxzn.wcs.utils.TaskUtils;
import com.yhy.wxzn.wcs.wcsWmsCommunication.ToWmsImpl;
import com.yhy.wxzn.wcs.wcsWmsCommunication.bean.TaskStatusRtn;
import com.yhy.wxzn.wcs.wcsWmsCommunication.bean.WmsTaskStatus;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.List;

import static com.yhy.wxzn.wcs.SystemInit.Lifter_Connection;
import static com.yhy.wxzn.wcs.device.rgv.FourWayRgvTaskExecuteThread.RGV_THREAD_LOCAL;


@Slf4j
public class FourWayTaskHandler implements TaskHandler{
    private WcsTask task;
    private FourWayRgv rgv;
    private WcsMapInfoServiceImpl mapInfoService = SpringUtil.getBean(WcsMapInfoServiceImpl.class);
    private WcsTaskServiceImpl taskService = SpringUtil.getBean(WcsTaskServiceImpl.class);
    private ToWmsImpl toWms = SpringUtil.getBean(ToWmsImpl.class);


    public FourWayTaskHandler(WcsTask task){
        this.task = task;
    }

    @Override
    public void handleTask() {
        beforeRunToStart();

        runToStart();

        runToEnd();

        afterRunToEnd();
    }

    private void afterRunToEnd() {
        this.task = taskService.updateRgvProgress(task,RgvProgress.RGV_COMPLETE);
        if (task.getTaskType() ==TaskType.IN
                || task.getTaskType() ==TaskType.TRANSFER
                || task.getTaskType() ==TaskType.MOVE_LOADED
                || task.getTaskType() ==TaskType.MOVE_UNLOADED
                || task.getTaskType() ==TaskType.CHARGE){
            this.task = taskService.updateTaskStatus(task,TaskStatus.FINISH);
            if (StrUtil.isNotEmpty(task.getWmsTaskId()))
                toWms.executionPhase(TaskStatusRtn.buildTaskStatusRtn(task.getWmsTaskId(), WmsTaskStatus.FINISH));
        }

        //todo 非提升机接驳点取消注释
//        if (task.getTaskType() == TaskType.OUT)
//            PlcTaskThread.executeTask(task);


        if (Lifter_Connection){
            if (task.getTaskType() == TaskType.OUT){
                WcsTask task = taskService.getFirstCanExecuteTask(rgv.getDeviceInfo().getId());
                if (task == null){
                    Node curLocation = rgv.getCurLocation();
                    List<Node> map = mapInfoService.getNodes(curLocation, curLocation);
                    Node nearestAvoidNode = new AvoidHandler(map).getNearestAvoidNode2(rgv);

                    if (nearestAvoidNode == null) {
                        throw new RuntimeException("生成空载任务点失败");
                    }

                    generateUnLoadTask(rgv, nearestAvoidNode);
                }
            }
        }
    }

    private void generateUnLoadTask(FourWayRgv rgv, Node nearestAvoidNode) {
        WcsTask task = TaskUtils.generateRgvTask(TaskType.MOVE_UNLOADED, null, nearestAvoidNode, PriorityCodes.MANUAL, rgv);
        taskService.save(task);
    }



    private void beforeRunToStart() {
        this.rgv = RGV_THREAD_LOCAL.get();

        this.task = taskService.updateTaskStatus(task, TaskStatus.ON_GOING);

        if (task.getRgvProgress().eq(RgvProgress.ASSIGNED_TO_RGV))
            this.task = taskService.updateRgvProgress(task,RgvProgress.RGV_TO_RUN);

        if (StrUtil.isNotEmpty(task.getWmsTaskId()))
            toWms.executionPhase(TaskStatusRtn.buildTaskStatusRtn(task.getWmsTaskId(), WmsTaskStatus.START));
    }


    private void runToStart() {
        if (StrUtil.isEmpty(task.getStart()) || task.getRgvProgress().gt(RgvProgress.RGV_TO_START))
            return;

        this.task = taskService.updateRgvProgress(task,RgvProgress.RGV_TO_START);

        if (rgv.getFourCarPlc().getPalletStatus() == PalletStatus.UP){
            throw new RuntimeException("托盘状态为举升，无法去取货");
        }

        //执行
        boolean retry = true;
        while (retry){
            try {
                rgv.checkIntercept("runToStart");

                List<Route> routes = generateRunToStartRoutes();

                new PathExecuteHandler(task).executePath(routes);

                runToStartAfterAction();

                retry = false;
            }catch (PalletUpStatusException e){

            }catch (PalletDownStatusException e){

            }catch (AddLockTimeOutException e){

            }catch (ActivelyAvoidFailureException e){

            }
        }

        //解锁
    }




    private void runToEnd(){
        if (task.getRgvProgress().eq(RgvProgress.RGV_COMPLETE)) return;

        this.task = taskService.updateRgvProgress(task,RgvProgress.RGV_TO_END);


        if(rgv.getFourCarPlc().getPalletStatus() == PalletStatus.UP
                && (task.getTaskType().equals(TaskType.MOVE_UNLOADED)
                || task.getTaskType().equals(TaskType.CHARGE))){
            throw new RuntimeException(String.format("托盘状态为举升，无法去执行%s任务",task.getTaskType().getDescription()));
        }

        if(rgv.getFourCarPlc().getPalletStatus() == PalletStatus.DOWN
                && (task.getTaskType().equals(TaskType.OUT)
                || task.getTaskType().equals(TaskType.IN)
                || task.getTaskType().equals(TaskType.TRANSFER)
                || task.getTaskType().equals(TaskType.MOVE_LOADED))){
            throw new RuntimeException(String.format("托盘状态为下降，无法去执行%s任务",task.getTaskType().getDescription()));
        }


        //执行
        boolean retry = true;
        while (retry){
            try {
                rgv.checkIntercept("runToEnd");



                //入库任务等待起点接驳点有货
                //出库任务 起点没货直接报错，然后举升、到终点，终点有货需要等待
                //todo 接驳点不为提升机启用
                //runToEndBeforeCheck();


                List<Route> routes = generateRunToEndRoutes();

                new PathExecuteHandler(task).executePath(routes);


                runToEndAfterAction();


                retry = false;
            }catch (PalletUpStatusException e){

            }catch (PalletDownStatusException e){

            }catch (AddLockTimeOutException e){

            }catch (ActivelyAvoidFailureException e){

            }
        }

        //解锁
    }


    private List<Route> generateRunToStartRoutes() {
        Node start = rgv.getCurLocationAndRefreshRgvLocation();
        Node end = new Node(Node.parseCoord(task.getStart()));
        List<Node> map = mapInfoService.getNodes(start,end);
        return new PathPlaningHandlerImpl(map).calculatePath(start, end, false);
    }

    private List<Route> generateRunToEndRoutes() {
        Node start = rgv.getCurLocationAndRefreshRgvLocation();
        Node end = new Node( Node.parseCoord(task.getEnd()));
        List<Node> map = mapInfoService.getNodes(start,end);
        boolean palletStatus = TaskType.CHARGE.equals(task.getTaskType()) || TaskType.MOVE_UNLOADED.equals(task.getTaskType()) ? false: true;

        return new PathPlaningHandlerImpl(map).calculatePath(start, end, palletStatus);
    }

    private void runToEndAfterAction() {
        if (task.getTaskType().equals(TaskType.IN)
                || task.getTaskType().equals(TaskType.OUT)
                || task.getTaskType().equals(TaskType.TRANSFER)){
            if (Node.parseCoord(task.getEnd()).equals(rgv.getCurLocationAndRefreshRgvLocation())){
                ToRgv.getInstance(rgv).palletDown();
                mapInfoService.cargoStatusByCoordStr(task.getEnd(),NodeStatus.Y.toString());
                if (StrUtil.isNotEmpty(task.getWmsTaskId()))
                    toWms.executionPhase(TaskStatusRtn.buildTaskStatusRtn(task.getWmsTaskId(), WmsTaskStatus.PUT_FINISH));
            }
        }
    }


    private void runToStartAfterAction() {
        if (task.getTaskType().equals(TaskType.IN)
                || task.getTaskType().equals(TaskType.OUT)
                || task.getTaskType().equals(TaskType.TRANSFER)

        ){
            Coord coord = Node.parseCoord(task.getStart());
            Node rgvCurLocation = rgv.getCurLocation();
            if (coord.getX() ==rgvCurLocation.getX() && coord.getY() == rgvCurLocation.getY()){
                ToRgv.getInstance(rgv).palletUp();
                mapInfoService.cargoStatusByCoordStr(task.getStart(),NodeStatus.N.toString());
                if (StrUtil.isNotEmpty(task.getWmsTaskId()))
                    toWms.executionPhase(TaskStatusRtn.buildTaskStatusRtn(task.getWmsTaskId(), WmsTaskStatus.GET_FINISH));
            }
        }
    }

    /**
     * 起点检查有无货物
     */
    private void runToEndBeforeCheck(){
        Node node = rgv.getCurLocationAndRefreshRgvLocation();
        while (task.getTaskType().equals(TaskType.IN)
                && node.getNodeType().equals(NodeType.CONNECTION)
                && RgvProgress.RGV_TO_END.gt(task.getRgvProgress())
                && !mapInfoService.isCanGet(node)){
            rgv.checkIntercept("beforeCheck");
            log.info("{}等待接驳点{}货物能取",rgv.getName(),node);
            WcsUtils.sleep(1000);
        }




        if ((task.getTaskType().equals(TaskType.OUT)
                || task.getTaskType().equals(TaskType.TRANSFER))
                && RgvProgress.RGV_TO_END.gt(task.getRgvProgress())
                && mapInfoService.getNode(node).getNodeStatus().equals(NodeStatus.N)){
            throw new RuntimeException(String.format("%s起点无货，无法执行%s任务",node,task.getTaskType().getDescription()));
        }

    }


}
